package com.sgj.controller;

import com.alibaba.fastjson.JSONObject;
import com.sgj.utils.Arith;
import com.sgj.utils.WxAPIV3AesUtil;
import com.sgj.vo.ALICallbackVo;
import com.sgj.vo.WXCallbackDecryptVo;
import com.sgj.vo.WXCallbackDecryptVo.*;
import com.sgj.vo.WXCallbackVo;
import com.sgj.vo.WXCallbackVo.*;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
import java.security.GeneralSecurityException;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;

/**
 * 支付宝或微信回调接口
 * @Author: Guoji Shen
 * @Date: 2021/12/1 9:34
 */
@Slf4j
@RestController
@RequestMapping("/callback")
public class CallBackController {

    @Value("${wxpay.apiv3PrivateKey}")
    private String WX_APIV3PRIVATEKEY;

    @PostMapping("/wx")
    public Map<String, Object> wxNotify(@RequestBody WXCallbackVo vo) throws IOException, GeneralSecurityException {
        log.info("[CallBackController][wxNotify] 微信回调成功:{}", JSONObject.toJSONString(vo));
        Map<String, Object> map = new HashMap<>();
        Resource resource = vo.getResource();

        // 回调数据解密
        WxAPIV3AesUtil aesUtil = new WxAPIV3AesUtil(WX_APIV3PRIVATEKEY.getBytes("UTF-8"));
        String decryptToString = aesUtil.decryptToString(resource.getAssociated_data().getBytes("UTF-8"),
                resource.getNonce().getBytes("UTF-8"), resource.getCiphertext());
        log.info("[CallBackController][wxNotify] 解密参数为:{}", JSONObject.toJSONString(decryptToString));

        // 解密值转换对应实体类
        WXCallbackDecryptVo wxCallbackDecryptVo = JSONObject.parseObject(decryptToString, WXCallbackDecryptVo.class);

        if (Objects.isNull(wxCallbackDecryptVo)) {
            throw new RuntimeException("微信支付回调解密失败");
        }

        if ("SUCCESS".equals(wxCallbackDecryptVo.getTrade_state())) {
            log.info("[CallBackController][wxNotify] 微信支付成功");
            // 支付成功
            // TODO 根据回调的商户订单号查询本地生成订单，判断金额是否正确
            Amount amount = wxCallbackDecryptVo.getAmount();
            // 因为微信金额单位为分，最终金额需要乘以100
            Integer finalAmount = (int) (Arith.divMore(amount, 100));

            // TODO 对比用户支付金额与订单是否一致,且是否已经支付过该订单,保证幂等性
            // if (finalAmount.equals(order.getAmount()) && "1".equals(order.getState())) {
            if(true) {
                log.info("[CallBackController][wxNotify] 用户支付与商户实收金额一致");
                // TODO 处理商户内部订单业务

                // 微信返回值
                map.put("code", "SUCCESS");
                map.put("message", "成功");
            } else {
                log.error("[CallBackController][wxNotify] 用户支付与商户实收金额不一致或该订单已支付");
                // 微信返回值
                map.put("code", "FAIL");
                map.put("message", "用户支付与商户实收金额不一致");
            }
        } else {
            log.error("[CallBackController][wxNotify] 支付失败");
            // 微信返回值
            map.put("code", "FAIL");
            map.put("message", "失败");
        }
        return map;
    }

    @PostMapping("/ali")
    public String aliNotify(HttpServletRequest request){
        // 解析回调 json，转换成对应实体
        String json = JSONObject.toJSONString(request.getParameterMap()).replace("[", "")
                .replace("]", "").replace("\\", "").replace("\\\"", "")
                .replace("\"{", "{").replace("}\"", "}");

        ALICallbackVo vo = JSONObject.parseObject(json, ALICallbackVo.class);
        log.info("[CallBackController][aliNotify] 支付宝回调成功:{}", JSONObject.toJSONString(vo));

        if (Objects.isNull(vo)) {
            throw new RuntimeException("支付宝支付回调无法解析");
        }

        if ("TRADE_SUCCESS".equals(vo.getTrade_status())) {
            log.info("[CallBackController][aliNotify] 支付宝支付成功");
            // TODO 根据回调的商户订单号查询本地生成订单，判断金额是否正确
            Double finalAmount = vo.getTotal_amount().doubleValue();

            // 对比用户支付金额与订单是否一致,且是否已经支付过该订单,保证幂等性
            // if (finalAmount == order.getAmount().doubleValue() && "1".equals(order.getState())) {
            if(true) {
                log.info("[CallBackController][aliNotify] 用户支付与商户实收金额一致");
                // TODO 处理商户内部订单业务

            } else {
                log.error("[CallBackController][aliNotify] 用户支付与商户实收金额不一致或该订单已支付");
                return "false";
            }
        } else {
            log.error("[CallBackController][aliNotify] 支付失败");
            return "false";
        }
        // 如果商户反馈给支付宝的字符不是 success 这 7 个字符，支付宝服务器会不断重发通知，直到超过 24 小时 22 分钟。一般情况下，25 小时以内完成 8 次通知（通知的间隔频率一般是：4m,10m,10m,1h,2h,6h,15h）
        return "success";
    }
}